package com.example.demo.executor;

import com.example.demo.entity.ExecuteInformationEntity;
import com.example.demo.entity.RelatedExecuteInformationEntity;
import com.example.demo.executor.backupDeal.BackupDealEnum;
import com.example.demo.executor.sqlGenerate.SqlGenerator;
import com.example.demo.executor.sqlGenerate.SqlGeneratorFactory;
import com.example.demo.typeEnums.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class MainTableExecutor implements Executor {

    @Autowired
    private SQLExecutor sqlExecutor;

    @Autowired
    private SqlGeneratorFactory sqlGeneratorFactory;

    @Autowired
    @Qualifier("relatedTableExecutor")
    private Executor relatedTableExecutor;

    @Autowired
    @Qualifier("mainTableExecutor")
    private Executor mainTableExecutor;

    @Value("${data.single.process.size}")
    public int MAX_SIZE;

    @Value("${database.software.name}")
    private String databaseSoftwareName;

    @Override
    public boolean execute(ExecuteInformationEntity informationEntity) {
        try {
            SqlGenerator sqlGenerator = sqlGeneratorFactory.getSqlGenerator(databaseSoftwareName);
            if (sqlGenerator == null) {
                throw new NullPointerException();
            }
            // 外部传入的数据不可靠，需要重新处理
            String executeType = ExecuteType.getExecuteType(informationEntity.getExecuteType(), null).getName();
            String backupDealType = BackupDealEnum.getBackupDealType(informationEntity.getBackupDealType());

            Integer maxSize = informationEntity.getMaxSize();
            if (maxSize == null || maxSize <= 0) {
                maxSize = MAX_SIZE;
            }
            String tableName = informationEntity.getTableName();
            String primaryKey = informationEntity.getPrimaryKey();
            String condition = sqlGenerator.generateExecuteConditionSql(informationEntity);
            // 得到符合条件的数据量
            Integer dealSize = this.getNeedDealDataSize(informationEntity, condition);

            if(dealSize > 0) {
                // 得到跟主表与关联表的关联的字段名
                List<String> columns = new ArrayList<>();
                List<RelatedExecuteInformationEntity> relatedInfos = informationEntity.getRelatedExecuteInformation();
                if (!CollectionUtils.isEmpty(relatedInfos)) {
                    columns = relatedInfos.stream().filter(e -> StringUtils.isNotBlank(e.getParentColumn()))
                            .map(RelatedExecuteInformationEntity::getParentColumn).collect(Collectors.toList());
                }
                columns.add(informationEntity.getPrimaryKey());
                String paramQuerySql = sqlGenerator.generateAllParamQuerySql(informationEntity.getTableName(), columns, condition);

                for (int i = 0; i < dealSize; i += maxSize) {
                    Integer size = (i + maxSize <= dealSize ? maxSize : dealSize - i);
                    paramQuerySql = sqlGenerator.generatePartParamQuerySql(paramQuerySql,
                            informationEntity.getSortColumn(), informationEntity.getSortType(), size);
                    Map<String, List<Object>> params = sqlExecutor.queryRelatedParam(paramQuerySql,columns);
                    // 按照条件查询不到数据时，结束当前数据的处理
                    if(params.size()==0){
                        break;
                    }
                    mainTableExecutor.singleCycleDataDeal(params, tableName, primaryKey, executeType, backupDealType, relatedInfos);
                }
            }
            return true;
        }catch (Exception e){
            log.error("There is a error!","exception", e);
            throw e;
        }
    }

    /**
     * 得到需要删除的数量
     * 按数量保留时：返回数据库中的总数 - 保留的条数；其它：返回Integer.MAX_VALUE
     */
    private Integer getNeedDealDataSize(ExecuteInformationEntity informationEntity, String condition){
        ReservedType reserveType = ReservedType.getReservedType(informationEntity.getReserveType(),null);
        Integer dealSize = Integer.MAX_VALUE;
        // 设置保留一定数量时，删除条数取
        if (ReservedType.QUANTITY.equals(reserveType)) {
            Integer allSize = sqlExecutor.getAmountOfDataInTable(informationEntity.getTableName());
            dealSize = allSize > informationEntity.getReserveSize() ? allSize - informationEntity.getReserveSize() : 0;
        }
        return dealSize;
    }

    @Transactional(transactionManager = "targetTransactionManager")
    public void singleCycleDataDeal(Map<String, List<Object>> params, String tableName, String primaryKey,
                                    String executeType, String backupDealType, List<RelatedExecuteInformationEntity> relatedInfos){
        sqlExecutor.dataProcess(tableName,primaryKey,params.get(primaryKey),executeType,backupDealType);
        // 执行关联的数据处理
        if(!CollectionUtils.isEmpty(relatedInfos)) {
            for (RelatedExecuteInformationEntity relatedInfo : relatedInfos) {
                List<Object> conditions = params.get(relatedInfo.getParentColumn());
                relatedTableExecutor.execute(conditions, relatedInfo);
            }
        }
    }

}
